1 using UnityEngine;
2 using
System.Collections;
3
4
5 public
class PickupCamera : Photon.MonoBehaviour
6 {
7
8     
public Transform cameraTransform;
9     
private Transform _target;
10
11     
// The distance in the x-z plane to the target
12
13     
public float distance = 7.0f;
14
15     
// the height we want the camera to be above the target
16     
public float height = 3.0f;
17
18     
public float angularSmoothLag = 0.3f;
19     
public float angularMaxSpeed = 15.0f;
20
21     
public float heightSmoothLag = 0.3f;
22
23     
public float snapSmoothLag = 0.2f;
24     
public float snapMaxSpeed = 720.0f;
25
26     
public float clampHeadPositionScreenSpace = 0.75f;
27
28     
public float lockCameraTimeout = 0.2f;
29
30     
private Vector3 headOffset = Vector3.zero;
31     
private Vector3 centerOffset = Vector3.zero;
32
33     
private float heightVelocity = 0.0f;
34     
private float angleVelocity = 0.0f;
35     
private bool snap = false;
36     
private PickupController controller;
37     
private float targetHeight = 100000.0f;
38
39     
private Camera m_CameraTransformCamera;
40
41     
void OnEnable()
42     {
43         
if( this.photonView != null && !this.photonView.isMine )
44         {
45             
this.enabled = false;
46             
return;
47         }
48
49         
if( !cameraTransform && Camera.main )
50             cameraTransform = Camera.main.transform;
51         
if( !cameraTransform )
52         {
53             Debug.Log(
"Please assign a camera to the ThirdPersonCamera script." );
54             enabled =
false;
55         }
56
57         m_CameraTransformCamera = cameraTransform.GetComponent<Camera>();
58
59
60         _target = transform;
61         
if( _target )
62         {
63             controller = _target.GetComponent<PickupController>();
64         }
65
66         
if( controller )
67         {
68             CharacterController characterController = (CharacterController)_target.GetComponent<Collider>();
69             centerOffset = characterController.bounds.center - _target.position;
70             headOffset = centerOffset;
71             headOffset.y = characterController.bounds.max.y - _target.position.y;
72         }
73         
else
74             Debug.Log(
"Please assign a target to the camera that has a ThirdPersonController script attached." );
75
76
77         Cut( _target, centerOffset );
78     }
79
80     
void DebugDrawStuff()
81     {
82         Debug.DrawLine( _target.position, _target.position + headOffset );
83
84     }
85
86     
float AngleDistance( float a, float b )
87     {
88         a = Mathf.Repeat( a,
360 );
89         b = Mathf.Repeat( b,
360 );
90
91         
return Mathf.Abs( b - a );
92     }
93
94     
void Apply( Transform dummyTarget, Vector3 dummyCenter )
95     {
96         
// Early out if we don't have a target
97         
if( !controller )
98             
return;
99
100         Vector3 targetCenter = _target.position + centerOffset;
101         Vector3 targetHead = _target.position + headOffset;
102
103         
// DebugDrawStuff();
104
105         
// Calculate the current & target rotation angles
106         
float originalTargetAngle = _target.eulerAngles.y;
107         
float currentAngle = cameraTransform.eulerAngles.y;
108
109         
// Adjust real target angle when camera is locked
110         
float targetAngle = originalTargetAngle;
111
112         
// When pressing Fire2 (alt) the camera will snap to the target direction real quick.
113         
// It will stop snapping when it reaches the target
114         
if( Input.GetButton( "Fire2" ) )
115             snap =
true;
116
117         
if( snap )
118         {
119             
// We are close to the target, so we can stop snapping now!
120             
if( AngleDistance( currentAngle, originalTargetAngle ) < 3.0f )
121                 snap =
false;
122
123             currentAngle = Mathf.SmoothDampAngle( currentAngle, targetAngle,
ref angleVelocity, snapSmoothLag, snapMaxSpeed );
124         }
125         
// Normal camera motion
126         
else
127         {
128             
if( controller.GetLockCameraTimer() < lockCameraTimeout )
129             {
130                 targetAngle = currentAngle;
131             }
132
133             
// Lock the camera when moving backwards!
134             
// * It is really confusing to do 180 degree spins when turning around.
135             
if( AngleDistance( currentAngle, targetAngle ) > 160 && controller.IsMovingBackwards() )
136                 targetAngle +=
180;
137
138             currentAngle = Mathf.SmoothDampAngle( currentAngle, targetAngle,
ref angleVelocity, angularSmoothLag, angularMaxSpeed );
139         }
140
141
142         
// When jumping don't move camera upwards but only down!
143         
if( controller.IsJumping() )
144         {
145             
// We'd be moving the camera upwards, do that only if it's really high
146             
float newTargetHeight = targetCenter.y + height;
147             
if( newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5 )
148                 targetHeight = targetCenter.y + height;
149         }
150         
// When walking always update the target height
151         
else
152         {
153             targetHeight = targetCenter.y + height;
154         }
155
156         
// Damp the height
157         
float currentHeight = cameraTransform.position.y;
158         currentHeight = Mathf.SmoothDamp( currentHeight, targetHeight,
ref heightVelocity, heightSmoothLag );
159
160         
// Convert the angle into a rotation, by which we then reposition the camera
161         Quaternion currentRotation = Quaternion.Euler(
0, currentAngle, 0 );
162
163         
// Set the position of the camera on the x-z plane to:
164         
// distance meters behind the target
165         cameraTransform.position = targetCenter;
166         cameraTransform.position += currentRotation * Vector3.back * distance;
167
168         
// Set the height of the camera
169         cameraTransform.position =
new Vector3( cameraTransform.position.x, currentHeight, cameraTransform.position.z );
170
171         
// Always look at the target
172         SetUpRotation( targetCenter, targetHead );
173     }
174
175     
void LateUpdate()
176     {
177         Apply( transform, Vector3.zero );
178     }
179
180     
void Cut( Transform dummyTarget, Vector3 dummyCenter )
181     {
182         
float oldHeightSmooth = heightSmoothLag;
183         
float oldSnapMaxSpeed = snapMaxSpeed;
184         
float oldSnapSmooth = snapSmoothLag;
185
186         snapMaxSpeed =
10000;
187         snapSmoothLag =
0.001f;
188         heightSmoothLag =
0.001f;
189
190         snap =
true;
191         Apply( transform, Vector3.zero );
192
193         heightSmoothLag = oldHeightSmooth;
194         snapMaxSpeed = oldSnapMaxSpeed;
195         snapSmoothLag = oldSnapSmooth;
196     }
197
198     
void SetUpRotation( Vector3 centerPos, Vector3 headPos )
199     {
200         
// Now it's getting hairy. The devil is in the details here, the big issue is jumping of course.
201         
// * When jumping up and down we don't want to center the guy in screen space.
202         
// This is important to give a feel for how high you jump and avoiding large camera movements.
203         
//
204         
// * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth.
205         
//
206         
// So here is what we will do:
207         
//
208         
// 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis
209         
// 2. When grounded we make him be centered
210         
// 3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold
211         
// 4. When landing we smoothly interpolate towards centering him on screen
212         Vector3 cameraPos = cameraTransform.position;
213         Vector3 offsetToCenter = centerPos - cameraPos;
214
215         
// Generate base rotation only around y-axis
216         Quaternion yRotation = Quaternion.LookRotation(
new Vector3( offsetToCenter.x, 0, offsetToCenter.z ) );
217
218         Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height;
219         cameraTransform.rotation = yRotation * Quaternion.LookRotation( relativeOffset );
220
221         
// Calculate the projected center position and top position in world space
222         Ray centerRay = m_CameraTransformCamera.ViewportPointToRay(
new Vector3( 0.5f, 0.5f, 1 ) );
223         Ray topRay = m_CameraTransformCamera.ViewportPointToRay(
new Vector3( 0.5f, clampHeadPositionScreenSpace, 1 ) );
224
225         Vector3 centerRayPos = centerRay.GetPoint( distance );
226         Vector3 topRayPos = topRay.GetPoint( distance );
227
228         
float centerToTopAngle = Vector3.Angle( centerRay.direction, topRay.direction );
229
230         
float heightToAngle = centerToTopAngle / ( centerRayPos.y - topRayPos.y );
231
232         
float extraLookAngle = heightToAngle * ( centerRayPos.y - centerPos.y );
233         
if( extraLookAngle < centerToTopAngle )
234         {
235             extraLookAngle =
0;
236         }
237         
else
238         {
239             extraLookAngle = extraLookAngle - centerToTopAngle;
240             cameraTransform.rotation *= Quaternion.Euler( -extraLookAngle,
0, 0 );
241         }
242     }
243
244     Vector3 GetCenterOffset()
245     {
246         
return centerOffset;
247     }
248
249 }


The distance in the x-z plane to the target

the height we want the camera to be above the target

Early out if we don't have a target

DebugDrawStuff();

Calculate the current & target rotation angles

Adjust real target angle when camera is locked

When pressing Fire2 (alt) the camera will snap to the target direction real quick.

It will stop snapping when it reaches the target

We are close to the target, so we can stop snapping now!

Normal camera motion

Lock the camera when moving backwards!

* It is really confusing to do 180 degree spins when turning around.

When jumping don't move camera upwards but only down!

We'd be moving the camera upwards, do that only if it's really high

When walking always update the target height

Damp the height

Convert the angle into a rotation, by which we then reposition the camera

Set the position of the camera on the x-z plane to:

distance meters behind the target

Set the height of the camera

Always look at the target

Now it's getting hairy. The devil is in the details here, the big issue is jumping of course.

* When jumping up and down we don't want to center the guy in screen space.

This is important to give a feel for how high you jump and avoiding large camera movements.

* At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth.

So here is what we will do:

1. We first find the rotation around the y axis. Thus he is always centered on the y-axis

2. When grounded we make him be centered

3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold

4. When landing we smoothly interpolate towards centering him on screen

Generate base rotation only around y-axis

Calculate the projected center position and top position in world space




Trò chơi Tic-Tac-Toe, game đánh caro full source code 53.602 lượt xem

Gõ tìm kiếm nhanh...